package com.ilikesoup.instant.classifier;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @ClassName Action
 * @Description: 动作
 * @Author gaoxiang
 * @Date 2020/8/7 14:27
 * @Version V1.0
 *
 * 描述一种对 T 类型对象的一种动作，触发动作后会返回可选对象 E。
 *
 **/
@FunctionalInterface
public interface Action<T, E> {

    E trigger(T t);

     /*
        静态创建Action的方法
     */

    static <T, E> Action<T, E> consume(Consumer<T> consumer) {
        return new Action.ConsumeAction<>(consumer);
    }

    static <T, E> Action<T, E> consume(Consumer<T> consumer, E defVal) {
        return new Action.ConsumeAction<>(consumer, defVal);
    }

    static <T, E> Action<T, E> biConsume(BiConsumer<T, E> consumer, E parameter) {
        return new Action.ExConsumeAction<>(consumer, parameter);
    }

    static <T, E> Action<T, E> apply(Function<T, E> converter) {
        return new Action.ConvertAction<>(converter);
    }

    static <T, U, E> Action<T, E> apply(BiFunction<T, U, E> converter, U parameter) {
        return new Action.ExConvertAction<>(converter, parameter);
    }

    static <T, E> NamedAction<T, E> naming(String name, Action<T, E> action) {
        return new NamedAction<>(name, action);
    }

    /*
        Action 常用的实现类
     */

    /**
     * @ClassName ConsumeAction
     * @Description: 消费动作
     * @Author gaoxiang
     * @Date 2020/8/7 14:31
     * @Version V1.0
     **/
    class ConsumeAction<T, E> implements Action<T, E> {

        private final Consumer<T> consumer;

        private final E defVal;

        public ConsumeAction(Consumer<T> consumer) {
            this.consumer = consumer;
            this.defVal = null;
        }

        public ConsumeAction(Consumer<T> consumer, E defVal) {
            this.consumer = consumer;
            this.defVal = defVal;
        }

        @Override
        public E trigger(T t) {
            consumer.accept(t);
            return defVal;
        }

    }

    /**
     * @ClassName ConvertAction
     * @Description: 转换动作
     * @Author gaoxiang
     * @Date 2020/8/7 14:34
     * @Version V1.0
     **/
    class ConvertAction<T, E> implements Action<T, E> {

        private final Function<T, E> func;

        public ConvertAction(Function<T, E> func) {
            this.func = func;
        }

        @Override
        public E trigger(T t) {
            return func.apply(t);
        }

    }

    /**
     * @ClassName ExConsumeAction
     * @Description: 消费动作，扩展了可传入的参数
     * @Author gaoxiang
     * @Date 2020/8/7 14:50
     * @Version V1.0
     **/
    class ExConsumeAction<T, E> implements Action<T, E> {

        private final BiConsumer<T, E> biConsumer;

        private final E parameter;

        public ExConsumeAction(BiConsumer<T, E> biConsumer, E parameter) {
            this.biConsumer = biConsumer;
            this.parameter = parameter;
        }

        @Override
        public E trigger(T t) {
            biConsumer.accept(t, parameter);
            return parameter;
        }
    }

    /**
     * @ClassName ExConvertAction
     * @Description: 转换动作，扩展了可传入的参数
     * @Author gaoxiang
     * @Date 2020/8/7 14:57
     * @Version V1.0
     **/
    class ExConvertAction<T, U, E> implements Action<T, E> {

        private final BiFunction<T, U, E> biFunction;

        private final U parameter;

        public ExConvertAction(BiFunction<T, U, E> biFunction, U parameter) {
            this.biFunction = biFunction;
            this.parameter = parameter;
        }

        @Override
        public E trigger(T t) {
            return biFunction.apply(t, parameter);
        }
    }

    /**
     * @ClassName ActionChain
     * @Description: 动作链，按顺序执行多个动作，按动作顺序返回触发结果列表
     * @Author gaoxiang
     * @Date 2020/8/7 15:38
     * @Version V1.0
     **/
    class ActionChain<T> implements Action<T, List<Object>> {

        private final List<Action<T, ?>> actions;

        public ActionChain(List<Action<T, ?>> actions) {
            this.actions = actions;
        }

        public ActionChain(Action<T, ?>... actions) {
            this.actions = Arrays.asList(actions);
        }

        @Override
        public List<Object> trigger(T part) {
            List<Object> result = new ArrayList<>(actions.size());
            for (Action<T, ?> action : actions) {
                result.add(action.trigger(part));
            }
            return result;
        }

    }

    /**
     * @ClassName NamedActionChain
     * @Description: 含有命名的动作链，触发会返回动作链中已命名的动作触发结果
     * @Author gaoxiang
     * @Date 2020/8/7 16:00
     * @Version V1.0
     **/
    class NamedActionChain<T> implements Action<T, Map<String, Object>> {

        private final List<Action<T, ?>> actions;

        public NamedActionChain(List<Action<T, ?>> actions) {
            this.actions = actions;
        }

        public NamedActionChain(Action<T, ?>... actions) {
            this.actions = Arrays.asList(actions);
        }

        @Override
        public Map<String, Object> trigger(T part) {
            Map<String, Object> result = new LinkedHashMap<>();
            for (Action<T, ?> action : actions) {
                Object triggerResult = action.trigger(part);
                if(action instanceof NamedAction) {
                    result.put(((NamedAction<T, ?>) action).getName(), triggerResult);
                }
            }
            return result;
        }

    }

    /**
     * @ClassName NamedAction
     * @Description: 命名动作
     * @Author gaoxiang
     * @Date 2020/8/7 15:59
     * @Version V1.0
     **/
    class NamedAction<T, E> implements Action<T, E> {
        private final String name;
        private final Action<T, E> action;

        public NamedAction(String name, Action<T, E> action) {
            this.name = name;
            this.action = action;
        }

        public String getName() {
            return name;
        }

        public Action<T, E> getAction() {
            return action;
        }

        @Override
        public E trigger(T t) {
            return action.trigger(t);
        }
    }

}
